﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.MessagingCE;
using System.Xml.Serialization;
using System.IO;

namespace Interfaces
{
    public class MessageDispatcher : IDisposable
    {
        public class MessageEventArgs : EventArgs
        {
            public string QueueName { get; private set; }
        }

        public class DispatchMetaData
        {
            public enum Direction { Read, Write, Invalid };

            public MessageQueue Queue { get; private set; }
            public Direction Mode { get; private set; }
            public DateTime LastEvent { get; set; }

            public DispatchMetaData(MessageQueue q, Direction m)
            {
                Queue = q;
                Mode = m;
            }
        }

        protected Dictionary<string, DispatchMetaData> dpTable;

        public MessageDispatcher()
        {
            dpTable = new Dictionary<string, DispatchMetaData>();
        }


        public void RegisterMessageWriter(string name)
        {
            MessageQueue q = new MessageQueue(false, name);
            dpTable.Add(name, new DispatchMetaData(q, DispatchMetaData.Direction.Write));
        }

        public void RegisterMessageReader(string name, EventHandler handler)
        {
            MessageQueue q = new MessageQueue(true, name);
            q.DataOnQueueChanged += handler;
            dpTable.Add(name, new DispatchMetaData(q, DispatchMetaData.Direction.Read));
        }

        public void RemoveMessagePoint(string name)
        {
            dpTable[name].Queue.Close();
            dpTable.Remove(name);
        }

        // TODO: optimalize this
        public List<KeyValuePair<string, DispatchMetaData>> GetMessagePoints(string s)
        {
            List<KeyValuePair<string, DispatchMetaData>> list = new List<KeyValuePair<string, DispatchMetaData>>();
            foreach (KeyValuePair<string, DispatchMetaData> kp in dpTable)
            {
                if (kp.Key.StartsWith(s)) list.Add(kp);
            }
            return list;
        }

        public bool MultipointSend(string pattern, Message m)
        {
            foreach (KeyValuePair<string, DispatchMetaData> kp in dpTable)
            {
                if (kp.Key.StartsWith(pattern))
                {
                    this.Send(kp.Key, m);
                }
            }
            return true;
        }

        public bool Send(string qName, Message msg)
        {
            if (!dpTable.ContainsKey(qName) && dpTable[qName].Mode != DispatchMetaData.Direction.Write)
                return false;
            ReadWriteResult rwr = dpTable[qName].Queue.Send(msg);
            if (rwr == ReadWriteResult.OK)
            {
                dpTable[qName].LastEvent = DateTime.Now;
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool Receive(string qName, Message msg)
        {
            if (!dpTable.ContainsKey(qName) && dpTable[qName].Mode != DispatchMetaData.Direction.Read)
                return false;
            ReadWriteResult rwr = dpTable[qName].Queue.Receive(msg);
            if (rwr == ReadWriteResult.OK)
            {
                dpTable[qName].LastEvent = DateTime.Now;
                return true;
            }
            else
            {
                return false;
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    public class ApplicationEventMessage : Message
    {
        [Serializable]
        public class ApplicationEventArgs : EventArgs
        {
            public enum Operation { Attach, Detach, Invalid };

            public Operation Op { get; private set; }
            public Guid Guid { get; private set; }
            public string Name { get; private set; }

            public ApplicationEventArgs()
            {
                Op = Operation.Invalid;
            }

            public ApplicationEventArgs(Guid appId, Operation op)
            {
                Guid = appId;
                Op = op;
            }
        }

        public ApplicationEventArgs Args { get; private set; }

        public ApplicationEventMessage()
        {
            Args = new ApplicationEventArgs();
        }

        public ApplicationEventMessage(Guid appId, ApplicationEventArgs.Operation op)
        {
            Args = new ApplicationEventArgs(appId, op);
        }

        public override byte[] MessageBytes
        {
            get
            {
                XmlSerializer xs = new XmlSerializer(typeof(ApplicationEventArgs));
                MemoryStream ms = new MemoryStream();
                StreamWriter sw = new StreamWriter(ms);
                xs.Serialize(ms, Args);
                sw.Close();
                return ms.ToArray();
            }
            set
            {
                XmlSerializer xs = new XmlSerializer(typeof(ApplicationEventArgs));
                MemoryStream ms = new MemoryStream(value);
                StreamReader sr = new StreamReader(ms);
                Args = (ApplicationEventArgs)xs.Deserialize(ms);
                sr.Close();
            }
        }
    }

    public class SignalEventMessage : Message
    {
        public PositionEventArgs Args { get; private set; }

        public SignalEventMessage()
        {
            Args = new PositionEventArgs(new List<IPositionData>(), PositionEventArgs.Operation.Invalid);
        }

        public SignalEventMessage(PositionEventArgs args)
        {
            Args = args;
        }

        public override byte[] MessageBytes
        {
            get
            {
                XmlSerializer xs = new XmlSerializer(typeof(PositionEventArgs));
                MemoryStream ms = new MemoryStream();
                StreamWriter sw = new StreamWriter(ms);
                xs.Serialize(ms, Args);
                sw.Close();
                return ms.ToArray();
            }
            set
            {
                XmlSerializer xs = new XmlSerializer(typeof(PositionEventArgs));
                MemoryStream ms = new MemoryStream(value);
                StreamReader sr = new StreamReader(ms);
                Args = (PositionEventArgs)xs.Deserialize(ms);
                sr.Close();
            }
        }
    }

    public class MarkerMessage : Message
    {
        [Serializable]
        public class MarkerEventArgs : EventArgs
        {
            public enum Operation { New, Modify, Delete, Invalid };
            public Operation Op { get; private set; }

            public int Id { get; private set; }
            public IAbsoluteData Position { get; private set; }
            public int ProtoId { get; private set; }
            public string Text { get; private set; }
            public System.Drawing.Bitmap Image { get; private set; }

            public MarkerEventArgs(Operation op)
            {
                Op = op;
            }
        }

        public MarkerEventArgs Args { get; private set; }

        public MarkerMessage()
        {
            Args = new MarkerEventArgs(MarkerEventArgs.Operation.Invalid);
        }

        public MarkerMessage(MarkerEventArgs args)
        {
            Args = args;
        }

        public override byte[] MessageBytes
        {
            get
            {
                XmlSerializer xs = new XmlSerializer(typeof(MarkerEventArgs));
                MemoryStream ms = new MemoryStream();
                StreamWriter sw = new StreamWriter(ms);
                xs.Serialize(ms, Args);
                sw.Close();
                return ms.ToArray();
            }
            set
            {
                XmlSerializer xs = new XmlSerializer(typeof(MarkerEventArgs));
                MemoryStream ms = new MemoryStream(value);
                StreamReader sr = new StreamReader(ms);
                Args = (MarkerEventArgs)xs.Deserialize(ms);
                sr.Close();
            }
        }
    }

    public class ContextEventMessage : Message
    {
        [Serializable]
        public class ContextEventArgs : EventArgs
        {
            public enum Operation { New, Modify, Delete, Callback, Invalid };
            public Operation Op { get; private set; }

            public int id;
            public string description;
            public short minRelevance;
            public Guid eventHandlerGuid;
            public string[] members;

            public ContextEventArgs(Operation op)
            {
                Op = op;
            }
        }

        public ContextEventArgs Args { get; private set; }

        public ContextEventMessage()
        {
            Args = new ContextEventArgs(ContextEventArgs.Operation.Invalid);
        }

        public ContextEventMessage(ContextEventArgs args)
        {
            Args = args;
        }

        public override byte[] MessageBytes
        {
            get
            {
                XmlSerializer xs = new XmlSerializer(typeof(ContextEventArgs));
                MemoryStream ms = new MemoryStream();
                StreamWriter sw = new StreamWriter(ms);
                xs.Serialize(ms, Args);
                sw.Close();
                return ms.ToArray();
            }
            set
            {
                XmlSerializer xs = new XmlSerializer(typeof(ContextEventArgs));
                MemoryStream ms = new MemoryStream(value);
                StreamReader sr = new StreamReader(ms);
                Args = (ContextEventArgs)xs.Deserialize(ms);
                sr.Close();
            }
        }
    }
}
